package com.jz.main.io.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Main {
    private ServerSocketChannel server = null;
    private Selector selector = null;
    int port = 9090;


    /**
     * 初始化
     */
    public void initServer(){
        try {
            server = ServerSocketChannel.open();
            server.configureBlocking(false);
            server.bind(new InetSocketAddress(port));

            // 多路复用器：取决于系统，可能是select、poll、epoll任意一种
            // 这里会返回复用器的fd: 简称epfd
            selector = Selector.open();

            /**
             * Selector类别
             * select、poll: jvm会开辟数组，将fd保存,此时在jvm中
             * epoll: 调用底层函数,epoll_ctl(epfd,op,fd,event)，此时fd保存在内核中
             */
            server.register(selector, SelectionKey.OP_ACCEPT);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     *
     */
    public void start(){
        initServer();
        System.out.println("服务器启动了....");

        try {
            while (true){

                /**
                 * Selector类别
                 * select、poll: 内核的select(epfd)、poll(epfd)
                 * epoll: epoll.wait()
                 */
                if(selector.select(500) > 0){
                    // 得到复用器找到的状态变化的fd集合
                    Set<SelectionKey> keySet = selector.selectedKeys();
                    Iterator<SelectionKey> iterator = keySet.iterator();
                    while (iterator.hasNext()){
                        SelectionKey fd = iterator.next();
                        iterator.remove();// 之所以remove，防止每次遍历重复读取
                        if (fd.isAcceptable()){
                            // 如果这个fd是可接受的，走接收处理
                            acceptHandler(fd);
                        }
                    }
                }

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 这里处理新fd，开始监听
     * @param fd
     */
    private void acceptHandler(SelectionKey fd){
        ServerSocketChannel ssc = (ServerSocketChannel) fd.channel();
        try {
            SocketChannel client = ssc.accept(); // 接受新的fd
            client.configureBlocking(false);

            ByteBuffer buffer = ByteBuffer.allocate(8192);

            /**
             * Selector类别
             * select、poll: jvm会开辟数组，将fd保存,此时在jvm中
             * epoll: 调用底层函数,epoll_ctl(epfd,op,fd,event)，此时fd保存在内核中
             */
            client.register(selector,SelectionKey.OP_READ);
            System.out.println("---------------------------------");
            System.out.println("新客户端："+client.getRemoteAddress());
            System.out.println("---------------------------------");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    public static void main2(String[] args) {
        Object o = new Object();
        Selector selector = null;
        try {
            selector = Selector.open();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            int  i = selector.select(500);
        } catch (IOException e) {
            e.printStackTrace();
        }
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(16,32,2000, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(32), Executors.defaultThreadFactory(),null);
        threadPoolExecutor.execute(new Runnable() {
            @Override
            public void run() {

            }
        });
        new Thread().start();
    }

    public static void main(String[] args) {
        HashMap2 map = new HashMap2();
        for (int i = 0; i < 50; i++) {
            map.put(String.valueOf(i),String.valueOf(i));
        }
        Object aa = map.table;
        for (int i = 0; i < map.table.length; i++) {
            System.out.print(i);
            System.out.print(",");
            System.out.println(map.table[i] == null);
        }
        System.out.println();

    }
}
